//
//  StanfordEventsAppDelegate.m
//  StanfordEvents
//
//  Created by Gongmyung on 6/30/10.
//  Copyright __MyCompanyName__ 2010. All rights reserved.
//

#import "StanfordEventsAppDelegate.h"

#define EVENTLIST 0
#define MAPVIEW 1
#define LOCALEVENTS 2

@interface StanfordEventsAppDelegate (PrivateCoreDataStack)
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@end


@implementation StanfordEventsAppDelegate

@synthesize window;
@synthesize mapViewController;
@synthesize eventsListViewController;
@synthesize localEventsListViewController;
@synthesize filtersTableViewController;
@synthesize tabController;
@synthesize mapController;
@synthesize state;

#pragma mark -
#pragma mark Application lifecycle

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    //for testing only
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
    
    /*
     * Fetch all events from our database
     */
    NSManagedObjectContext *context = [self managedObjectContext];
    
    if (!context) {
        // ...wat?
    }
    
    NSError *error;
    /*
     * get stuff for our history tab
     */
    NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
    [request setEntity:[NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectContext]];
    [request setPredicate:[NSPredicate predicateWithFormat:@"mine==1 || attended==1"]];
    // describe how we want the data sorted
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"starttime" ascending:NO];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [request setSortDescriptors:sortDescriptors];
    NSMutableArray *results = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];    
    
    
    /*
     * get stuff for our map tab
     */
    NSFetchRequest *mapRequest = [[[NSFetchRequest alloc] init] autorelease];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectContext];    
    [mapRequest setEntity:entity];
    [mapRequest setSortDescriptors:sortDescriptors];
    [sortDescriptors release];
    [sortDescriptor release];
    //fetch the objects!
    NSMutableArray *mapFetchResults = [[managedObjectContext executeFetchRequest:mapRequest error:&error] mutableCopy];
    
    
    //initialize the tab controller
    tabController = [[UITabBarController alloc] init];
    
    //initialize the controllers
    myEventsController = [[UINavigationController alloc] init];
    mapController = [[UINavigationController alloc] init];
    localEventsController = [[UINavigationController alloc] init];
    filtersController = [[UINavigationController alloc] init];
    
    //setup the tab icons for myEvents, createEvent, and map
    UITabBarItem *myEventsItem = [[UITabBarItem alloc]
                                  initWithTitle:@"My Events" image:[UIImage imageNamed:@"83-calendar.png"] 
                                  tag:0];
    UITabBarItem *localEventsItem = [[UITabBarItem alloc]
                                     initWithTitle:@"Nearby" image:[UIImage imageNamed:@"112-group.png"] 
                                     tag:0];
    UITabBarItem *mapItem = [[UITabBarItem alloc]
                             initWithTitle:@"Map" image:[UIImage imageNamed:@"73-radar.png"] 
                             tag:0];
    UITabBarItem *filterItem = [[UITabBarItem alloc]
                                initWithTitle:@"Filters" image:[UIImage imageNamed:@"44-shoebox.png"] tag:0];
    myEventsController.tabBarItem = myEventsItem;
    [myEventsItem release];
    mapController.tabBarItem = mapItem;
    [mapItem release];
    localEventsController.tabBarItem = localEventsItem;
    [localEventsItem release];
    filtersController.tabBarItem = filterItem;
    [filterItem release];
    
    /*
     * Create the list of events
     */
    eventsListViewController = [[EventsListViewController alloc] initWithStyle:UITableViewStylePlain];
    [eventsListViewController setEventsArray:results];
    
    // Pass the managed object context to the view controller.
    eventsListViewController.managedObjectContext = context;
    
    [myEventsController pushViewController:eventsListViewController animated:NO];
    [eventsListViewController release];
    
    
    //initialize the map
	NSMutableArray *annotations = [[NSMutableArray alloc] init];
	for( Event *e in mapFetchResults ) {
        MapAnnotation *annotation = [[MapAnnotation alloc] initWithEvent:e];
        [annotations addObject:annotation]; 
        [annotation release];
	}
	mapViewController = [[MapViewController alloc] initWithArray:annotations];
	[annotations release];
    mapViewController.managedObjectContext = context;
	[mapController pushViewController:mapViewController animated:NO];
	[mapViewController release];
    
    //
    // create the nearby list view controller
    //
    localEventsViewController = [[LocalEventsListViewController alloc] initWithStyle:UITableViewStylePlain];
    [localEventsViewController setEventsArray:[[NSMutableArray alloc]init]];
    
    // Pass the managed object context to the view controller.
    localEventsViewController.managedObjectContext = context;
    
    [localEventsController pushViewController:localEventsViewController animated:NO];
    [localEventsViewController release];
    
    //
    // create the filters controller
    //
    NSFetchRequest *tagsRequest = [[NSFetchRequest alloc] init]; 
    [tagsRequest setEntity:[NSEntityDescription entityForName:@"Tag" inManagedObjectContext:managedObjectContext]];
    NSMutableArray *tags = [[managedObjectContext executeFetchRequest:tagsRequest error:&error] mutableCopy];
    filtersTableViewController = [[FiltersTableViewController alloc] initWithStyle:UITableViewStylePlain andTags:tags withContext:managedObjectContext];
    [filtersController pushViewController:filtersTableViewController animated:NO];
    [filtersTableViewController release];
    [tagsRequest release];
    
    /*
     * add all the navigation controllers to the tabcontroller
     */
    tabController.viewControllers = [NSArray arrayWithObjects: mapController, myEventsController, localEventsController, filtersController, nil];
    
    
    
    //check to see if we have a concierge login saved to our database already
    NSUserDefaults *defaultSettings = [NSUserDefaults standardUserDefaults];
    username = [defaultSettings stringForKey:@"username"];
    password = [defaultSettings stringForKey:@"password"];
    if (username == nil || password == nil ) {
        ConciergeLoginViewController *loginViewController = [[ConciergeLoginViewController alloc] initWithNibName:@"ConciergeLoginViewController" bundle:nil];
        loginViewController.delegate = self;
        [window addSubview:loginViewController.view];
        [window makeKeyAndVisible];
        
    }
    else {
        [window addSubview:tabController.view];
        [window makeKeyAndVisible];
        
    }
    
	return YES;
}

- (void) finished {
    [window addSubview:tabController.view];
    [window makeKeyAndVisible];
}

/*
 * Event handling
 */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    NSLog(@"remote notification recieved");
    //TODO: in the future add support for checking what type of notification it is
    
    //create spinny wheel
    /*
    UIActivityIndicatorView *av = [[[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray] autorelease];
    av.frame=CGRectMake(145, 160, 25, 25);
    av.tag = 1;
    //figure out what is currently on the screen&display the spinny wheel on top of that
    if( state == MAPVIEW ) {
        [mapController.visibleViewController.view addSubview:av];
    }
    else if( state == LOCALEVENTS ) {
        [localEventsController.visibleViewController.view addSubview:av];
    }
    [av startAnimating];
    */
    /*
     
    UIAlertView *alert = [[UIAlertView alloc]
                          initWithTitle:@"mid is:"
                          message:[NSString stringWithFormat:@"%@", [userInfo objectForKey:@"batch"]]
                          delegate:self
                          cancelButtonTitle:@"Ok"
                          otherButtonTitles: nil];
    [alert show];
    [alert autorelease];
    */
    
    //get the message from concierge
    NSDictionary *mid = [userInfo objectForKey:@"batch"];
    
    NSURL *url = [NSURL URLWithString:@"http://colby.stanford.edu/community_vibe/concierge/rpc.php"];
    ASIFormDataRequest *principalRequest = [ASIFormDataRequest requestWithURL:url];
    [principalRequest setPostValue:username forKey:@"name"];
    [principalRequest setPostValue:password forKey:@"key"];
    [principalRequest setPostValue:@"getBatch" forKey:@"do"];
    NSLog(@"Since: %@ Limit: %@", [mid objectForKey:@"0"], [mid objectForKey:@"1"]);
    [principalRequest setPostValue:[mid objectForKey:@"0"] forKey:@"since"];
    [principalRequest setPostValue:[mid objectForKey:@"1"] forKey:@"limit"];
    [principalRequest startSynchronous];
    NSString *response;
    NSError *error = [principalRequest error];
    if (!error) {
        response = [principalRequest responseString];
        NSLog(@"Reponse is: %@", response);
        
        if ( response.length != 0 ) {
            NSLog(@"downloaded response from concierge, about to parse it");
                /*
                NSDictionary *jsonResponseDict = [sparser objectWithString:response];
                NSString *taglist = [jsonResponseDict objectForKey:@"taglist"];
                if( [taglist hasPrefix:@"response, stanford_events"] ) {
                    NSLog(@"About to add events");
                    NSString *eventDataString = [jsonResponseDict objectForKey:@"content"];
                    eventData = [sparser objectWithString:eventDataString];
                  */  
            switch (state) {
                case EVENTLIST:
                    break;
                case MAPVIEW:
                    //[[NSNotificationCenter defaultCenter] postNotificationName:@"MapPushRecieved" object:self userInfo:eventDict];      
                    [mapViewController downloadFinished:response];
                    break;
                case LOCALEVENTS:
                    [localEventsViewController downloadFinished:response];
                    break;
                default:
                    break;
            }
        }
        
        //make the refreshbutton enabled on the mapview controller since the push was recieved
        if (state == MAPVIEW) {
            mapViewController.refreshButton.enabled = YES;
            mapViewController.refreshButton.alpha = 1.0f;
        }
        
        state = 0;
    }
    
    
    //get rid of spinny wheel
    //UIActivityIndicatorView *tmpimg = (UIActivityIndicatorView *)[yourView viewWithTag:1];
    //[av removeFromSuperview];
}


/**
 applicationWillTerminate: saves changes in the application's managed object context before the application terminates.
 */
- (void)applicationWillTerminate:(UIApplication *)application {
	
    NSError *error = nil;
    if (managedObjectContext != nil) {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
			/*
			 Replace this implementation with code to handle the error appropriately.
			 
			 abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
			 */
			NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
			abort();
        } 
    }
}


#pragma mark -
#pragma mark Remote notifications

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
   /* 
    UIAlertView *alert = [[UIAlertView alloc]
                                initWithTitle:@"Device token is:"
                                message:[NSString stringWithFormat:@"%@", [deviceToken description]]
                                delegate:self
                                cancelButtonTitle:@"Ok"
                                otherButtonTitles: nil];
    [alert show];
    [alert autorelease];
    */
    // You can send here, for example, an asynchronous HTTP request to your web-server to store this deviceToken remotely
    NSLog(@"Did register for remote notifications: %@", deviceToken);
    
    while( true ) {
    
        NSUserDefaults *defaultSettings = [NSUserDefaults standardUserDefaults];
        username = [defaultSettings stringForKey:@"username"];
        password = [defaultSettings stringForKey:@"password"];
    
        NSURL *url = [NSURL URLWithString:@"http://colby.stanford.edu/community_vibe/concierge/rpc.php"];
        ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
    
        [request setPostValue:username forKey:@"name"];
        [request setPostValue:password forKey:@"key"];
        [request setPostValue:@"updateDeviceToken" forKey:@"do"];
        [request setPostValue:deviceToken forKey:@"other"];
        [request startSynchronous];
    
        if( ![request error] ) {
            break;
        }
    }
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"Failed  to register for remote notifications: %@", error);
}


#pragma mark -
#pragma mark Core Data stack

/**
 Returns the managed object context for the application.
 If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
 */
- (NSManagedObjectContext *) managedObjectContext {
	
    if (managedObjectContext != nil) {
        return managedObjectContext;
    }
	
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        managedObjectContext = [[NSManagedObjectContext alloc] init];
        [managedObjectContext setPersistentStoreCoordinator: coordinator];
    }
    return managedObjectContext;
}


/**
 Returns the managed object model for the application.
 If the model doesn't already exist, it is created by merging all of the models found in the application bundle.
 */
- (NSManagedObjectModel *)managedObjectModel {
	
    if (managedObjectModel != nil) {
        return managedObjectModel;
    }
    managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];    
    return managedObjectModel;
}


/**
 Returns the persistent store coordinator for the application.
 If the coordinator doesn't already exist, it is created and the application's store added to it.
 */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
	
    if (persistentStoreCoordinator != nil) {
        return persistentStoreCoordinator;
    }
	
    NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"StanfordEvents.sqlite"]];
	
	NSError *error = nil;
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
		/*
		 Replace this implementation with code to handle the error appropriately.
		 
		 abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
		 
		 Typical reasons for an error here include:
		 * The persistent store is not accessible
		 * The schema for the persistent store is incompatible with current managed object model
		 Check the error message to determine what the actual problem was.
		 */
		NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
		abort();
    }    
	
    return persistentStoreCoordinator;
}


#pragma mark -
#pragma mark Application's Documents directory

/**
 Returns the path to the application's Documents directory.
 */
- (NSString *)applicationDocumentsDirectory {
	return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
}


#pragma mark -
#pragma mark Memory management

- (void)dealloc {
	
    [managedObjectContext release];
    [managedObjectModel release];
    [persistentStoreCoordinator release];
    
	[window release];
	[super dealloc];
}


@end

